package com.laolang.thresh.module.auth.service;

import cn.hutool.core.lang.UUID;
import com.laolang.thresh.module.auth.exception.AuthBusinessException;
import com.laolang.thresh.module.auth.propterties.AuthProperties;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Jwts.SIG;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import java.time.Instant;
import java.util.Date;
import java.util.Map;
import javax.crypto.SecretKey;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service;

/**
 * xxx.
 *
 * @author laolang
 * @version 0.1
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class TokenService {

    private final AuthProperties authProperties;

    /**
     * 加密算法.
     */
    private static final SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = SIG.HS256;


    /**
     * jwt 签发者.
     */
    private static final String jwtIss = "laolang";

    /**
     * jwt 主题.
     */
    private static final String jwtSubject = "thresh";

    /**
     * 生成 jwt.
     */
    public Tuple2<String, String> genJwt(Map<String, Object> payload, String secrect) {
        // 令牌 id
        String uuid = UUID.fastUUID().toString();
        // 到期时间
        Date expireDate = Date.from(
            Instant.now().plusSeconds(authProperties.getAccessExpire() * 60));

        // 使用每个用户的 secrect
        SecretKey userSecretKey = Keys.hmacShaKeyFor(secrect.getBytes());

        // 生成 token
        String token = Jwts.builder()
            // 设置头部信息
            .header()
            .add("typ", "JWT")
            .add("alg", "HS256")
            .and()
            // payload
            .claims(payload)
            // 令牌 id
            .id(uuid)
            // 过期时间
            .expiration(expireDate)
            // 签发时间
            .issuedAt(new Date())
            // 主题
            .subject(jwtSubject)
            // 签发者
            .issuer(jwtIss)
            // 签名
            .signWith(userSecretKey, algorithm)
            .compact();
        return Tuple.of(token, uuid);
    }

    /**
     * 解析 token.
     */
    public void verifyToken(String token, String secrect) {
        try {
            SecretKey userSecretKey = Keys.hmacShaKeyFor(secrect.getBytes());
            Jwts.parser().verifyWith(userSecretKey).build().parseSignedClaims(token);
        } catch (Exception e) {
            log.error("验证 token 失败. 原因:【{}】", ExceptionUtils.getMessage(e));
            throw AuthBusinessException.authTokenVerifyFailed();
        }
    }
}
